package org.tigr.htc.server.condor;

/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcClient;
import org.tigr.htc.common.HTCConfig;
import org.tigr.htc.common.SSHCommand;
import org.tigr.htc.server.mw.CalcTasks;

/**
 * The <b>CondorUtils</b> class - a grouping of static methods that 
 * interface to the Condor scheduler.
 *
 */
public class CondorUtils {
	static Logger log = Logger.getLogger(CondorUtils.class);

	// location of condor_submit
	final static String htc_submit = HTCConfig.getProperty("condor_submit");
	
	// location of condor_submit
	final static String PASS = HTCConfig.getProperty("passwd");

	final static String htc_user = HTCConfig.getProperty("htc_user");

	// location of condor_rm
	final static String htc_rm = HTCConfig.getProperty("condor_rm");

	final static String htc_base = HTCConfig.getProperty("htc_base");

	// location of condor_hold
	final static String htc_hold = HTCConfig.getProperty("condor_hold");

	// location of condor_release
	final static String htc_release = HTCConfig.getProperty("condor_release");
	
	/**
	 * The variable <code>peerList</code> keeps the list of peer servers that are active
	 */
	static public List peerList = Collections.synchronizedList(new Vector());
	
	 // client XML-RPC object to send procedure calls to server
    static private XmlRpcClient client;
    
    static public Map peerClients = new HashMap();
    
    static {
        try {
            initPeerList();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(1);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(1);
        } catch (RuntimeException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            System.exit(1);
        }
    }
	

	/**
	 * <code>submit</code> job to the grid as pUser using pSubmitFile 
	 *
	 * @return grid job id
	 * @exception Exception 
	 */
	public static int submit(File submitFile, String user,
			String machine, File logFile) throws Exception {
		int cid = -1;

		String submitCmd = htc_submit + " " + user + " " + submitFile.getAbsolutePath();
		log.debug("Submit command - " + submitCmd);
		SSHCommand sshCmd = new SSHCommand(machine, htc_user, PASS);
		int exitValue = sshCmd.runCommand(submitCmd);
		log.debug("Return value: " + exitValue);
		String line = sshCmd.getOutput();
		log.debug("condor_submit result " + line);

		String result = null;
		String code = null;
		if (line != null) {
			line = line.trim();
			int ind = line.indexOf(":");
			if (ind == -1) {
				throw new Exception("Submission error output was: " + line);
			}
			result = line.substring(ind + 1);
			code = line.substring(0, ind);
			log.debug("Code was " + code);
		} else {
			throw new Exception("Submission Error no ouput was returned");
		}

		// submit should have been successful since we got a zero
		if (code.indexOf("JobID") != -1) {
			cid = Integer.parseInt(result);
			log.debug("Cluster id was: " + cid);
		} else { // error happen
			throw new Exception("Submission Failure: " + result);
		}

		return cid;
	}


    /**
     * <code>remove</code> job with id from Condor
     *
     * @param pId a <code>int</code> 
     * @exception Exception 
     */
	public static boolean remove(int pId, String pMachine) throws Exception {
		SSHCommand sshCmd = new SSHCommand(pMachine, PASS);
		String condorCmd = htc_rm + " " + pId;
		
		log.info("Run command: " + condorCmd);
		int exitValue = sshCmd.runCommand(condorCmd);
		
		log.info("Return value :  " + exitValue);
		if (exitValue != 0) {
			return false;
		}
		
		return true;
	}
    

    /**
     * <code>hold</code> job with id from Condor
     *
     * @param pId a <code>int</code> 
     * @exception Exception 
     */
    public static boolean hold(int pId, String pMachine) throws Exception {
        SSHCommand sshCmd = new SSHCommand(pMachine, PASS);
        String condorCmd = htc_hold + " " + pId;

        log.debug("Run command: " + condorCmd);
        int exitValue = sshCmd.runCommand(condorCmd);

        log.debug("condor_hold Return value :  " + exitValue);
        if (exitValue != 0) {
            return false;
        }

        return true;
    }


    /**
     * <code>release</code> job with id from Condor
     *
     * @param id a <code>int</code> 
     * @exception Exception 
     */
    public static boolean release(int id, String machine) throws Exception {
    	SSHCommand sshCmd = new SSHCommand(machine, PASS);
    	String condorCmd = htc_release + " " +  id;
    	
    	log.debug("Run Command: " + condorCmd);
    	int exitValue = sshCmd.runCommand(condorCmd);
    	
    	log.debug("condor_release return value :  " + exitValue);
    	if (exitValue != 0) {
    		return false;
    	} 
    	
    	return true;
    }

	public static int initTasks(File file) throws Exception {
		int tasks = CalcTasks.calculateTaskSize(file.getAbsolutePath());
		return tasks;
	}
	
	public static void initPeerList() throws MalformedURLException, 
												IOException, RuntimeException {
	    // Get local host name
	    String hostName = InetAddress.getLocalHost().getHostName();
	    
	    // Open the file that lists the peers and add to the peer list
		String peerFile = HTCConfig.getPeerList();
		log.debug("Peer list file name is " + peerFile);
		LineNumberReader lnr = new LineNumberReader(new FileReader(peerFile));
		String peerName = null;
		while ((peerName = lnr.readLine()) != null) {
            log.info("Read peer name " + peerName);
            if (!peerName.equals(hostName)) {
                peerList.add(peerName);
                // Create the client needed to communicate with peer and add to map 
                String uri = "http://" + peerName + ":" + HTCConfig.getProperty("htc.service.port") +
                    HTCConfig.getProperty("htc.service.address");
                log.info("Creating RPC client for peer using URI: " + uri);
                client = new XmlRpcClient(uri);
                peerClients.put(peerName, client);
            }
        }
		lnr.close();	    	    
	}	
}
